// FeedService.cs
// Facebook/Framework/Service
// Copyright (c) 2008, Nikhil Kothari. All Rights Reserved.
//
// Total Re-write:
// Copyright (c) 2008, Paul Huff. All Rights Reserved.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Facebook.Service.Core;

namespace Facebook.Service {

    /// <summary>
    /// Represents the service APIs related to the user's feeds on Facebook.
    /// </summary>
    public sealed class FeedService {

        private FacebookSession _session;
        private FacebookResponse _lastResponse;

        internal FeedService(FacebookSession session) {
            Debug.Assert(session != null);
            _session = session;
        }

        /// <summary>
        /// The last response recevied through the Feed Service.  If a call failed you can check the error codes
        /// through this parameter and reference the Facebook Developer API Documentation for further help.
        /// </summary>
        public FacebookResponse LastResponse
        {
            get { return _lastResponse; }
        }
       
        /// <summary>
        /// Publishes a story on behalf of the user owning the session, using the specified template bundle. 
        /// This method requires an active session key in order to be called.
        /// 
        /// An application can publish a maximum of 10 stories per user per day. 
        /// </summary>
        /// <param name="story"></param>
        /// <returns></returns>
        public bool publishUserAction(FeedStory story)
        {
            FacebookRequest request = new FacebookRequest(_session);

            if (story.TemplateData != null)
            {
                StringBuilder templateDataBuilder = new StringBuilder();

                JsonWriter writer = new JsonWriter(new StringWriter(templateDataBuilder), /* minimizeWhitespace */ true);
                writer.WriteValue(story.TemplateData);

                if (story.Images != null)
                {
                    if (story.Images.Count > 0)
                    {
                        writer.WriteValue("images");
                        writer.WriteName(null);//null allows us to add a : and begin a Json Array with key/value pairs

                        //Begin Array Scope - '['
                        writer.StartArrayScope();
                        foreach (FeedImage image in story.Images)
                        {
                            //Begin Array Scope - '{'
                            writer.StartObjectScope();

                            writer.WriteName("src");
                            writer.WriteValue(image.ImageUrl);

                            writer.WriteName("href");
                            writer.WriteValue(image.ImageLinkUrl);

                            //End Array scope = '}'
                            writer.EndScope();
                        }

                        //End Array scope = ']'
                        writer.EndScope();
                    }
                }

                request.Parameters["template_data"] = templateDataBuilder.ToString();
            }

            request.Parameters["template_bundle_id"] = story.TemplateBundleID.ToString();

            if (story.TargetUserIDs != null)
            {
                StringBuilder targetIDsBuilder = new StringBuilder();
                foreach (string id in story.TargetUserIDs)
                {
                    if (targetIDsBuilder.Length != 0)
                    {
                        targetIDsBuilder.Append(",");
                    }
                    targetIDsBuilder.Append(id);
                }

                request.Parameters["target_ids"] = targetIDsBuilder.ToString();
            }

            if (String.IsNullOrEmpty(story.BodyGeneral) == false)
            {
                request.Parameters["body_general"] = story.BodyGeneral;
            }
            if (story.StorySize != null)
            {
                StringBuilder storySizeBuilder = new StringBuilder();

                JsonWriter writer = new JsonWriter(new StringWriter(storySizeBuilder), /* minimizeWhitespace */ true);
                writer.WriteValue((int)story.StorySize);

                request.Parameters["story_size "] = storySizeBuilder.ToString();
            }

            FacebookResponse response = request.InvokeMethod("feed.publishUserAction");

            // if the result is false (failed) this property allows the developer to get access to 
            // the error codes returned from Facebook.
            _lastResponse = response;

            if (response.Status == FacebookResponseStatus.Succeeded)
            {
                return FacebookResponse.CoerceBoolean(response.Result);
            }

            return false;
        }

        /// <summary>
        /// Builds a template bundle around the specified templates, registers them on Facebook, 
        /// and responds with a template bundle ID that can be used to identify your template bundle 
        /// to other Feed-related API calls.
        /// </summary>
        /// <param name="templateBundle"></param>
        /// <returns>Returns -1 if the call failed</returns>
        public int registerTemplateBundle(FeedTemplateBundle templateBundle)
        {
            if (templateBundle.OneLineStories == null)
                throw new ArgumentNullException("templateBundle.OneLineStories", "At least one One Line Story is required");
            if (templateBundle.OneLineStories.Stories == null)
                throw new ArgumentNullException("templateBundle.OneLineStories.Stories", "At least one One Line Story is required");
            if (templateBundle.OneLineStories.Stories.Length <= 0)
                throw new ArgumentNullException("templateBundle.OneLineStories.Stories.Length", "At least one One Line Story is required");

            int result = -1;

            FacebookRequest request = new FacebookRequest(_session);

            request.Parameters["format"] = "JSON";

            //GET ONE LINE STORIES
            StringBuilder storyBuilder = new StringBuilder();

            JsonWriter oneWriter = new JsonWriter(new StringWriter(storyBuilder), /* minimizeWhitespace */ true);

            oneWriter.StartArrayScope();
            foreach (var item in templateBundle.OneLineStories.Stories)
            {
                oneWriter.WriteValue(item);
            }
            oneWriter.EndScope();

            request.Parameters["one_line_story_templates"] = storyBuilder.ToString();
            oneWriter = null;

            //GET SHORT STORIES
            if (templateBundle.ShortStories != null)
            {
                StringBuilder shortStoryBuilder = new StringBuilder();

                JsonWriter shortWriter = new JsonWriter(new StringWriter(shortStoryBuilder), /* minimizeWhitespace */ true);

                // "["
                shortWriter.StartArrayScope();

                for (int i = 0; i < templateBundle.ShortStories.Stories.Length; i++)
                {

                    // "{"
                    shortWriter.StartObjectScope();
                    
                    shortWriter.WriteName("template_title");
                    shortWriter.WriteValue(templateBundle.ShortStories.Titles[i]);

                    shortWriter.WriteName("template_body");
                    shortWriter.WriteValue(templateBundle.ShortStories.Stories[i]);

                    // "}"
                    shortWriter.EndScope();
                }

                // "]"
                shortWriter.EndScope();

                request.Parameters["short_story_templates"] = shortStoryBuilder.ToString();
                shortWriter = null;
            }

            //GET FULL STORY
            if (templateBundle.ShortStories != null)
            {
                StringBuilder fullStoryBuilder = new StringBuilder();

                JsonWriter fullWriter = new JsonWriter(new StringWriter(fullStoryBuilder), /* minimizeWhitespace */ true);


                fullWriter.StartObjectScope();

                fullWriter.WriteName("template_title");
                fullWriter.WriteValue(templateBundle.FullStory.TitleTemplate);

                fullWriter.WriteName("template_body");
                fullWriter.WriteValue(templateBundle.FullStory.BodyTemplate);
                
                fullWriter.EndScope();

                request.Parameters["full_story_template"] = fullWriter.ToString();

                fullWriter = null;
            }
            
            //Call Facebook API
            FacebookResponse response = request.InvokeMethod("feed.registerTemplateBundle");

            // if the result is false (failed) this property allows the developer to get access to 
            // the error codes returned from Facebook.
            _lastResponse = response;

            if (response.Status != FacebookResponseStatus.Succeeded)
            {
                return result;
            }

            if (!int.TryParse(response.Result.ToString(), out result))
                result = -1;

            return result;
        }

        /// <summary>
        /// Retrieves information about a specified template bundle previously 
        /// registered by the requesting application. 
        /// </summary>
        /// <param name="ID"></param>
        /// <returns>A FeedTemplateBundle object or null if no template registered under ID.</returns>
        public FeedTemplateBundle getRegisteredTemplateBundleByID(int ID)
        {
            FacebookRequest request = new FacebookRequest(_session);

            //Call Facebook API
            FacebookResponse response = request.InvokeMethod("feed.registerTemplateBundle");

            // if the result is false (failed) this property allows the developer to get access to 
            // the error codes returned from Facebook.
            _lastResponse = response;

            if (response.Status != FacebookResponseStatus.Succeeded)
                return null;

            return getTemplateBundleFromResponse(response.Result);
        }


        //TODO:
        private FeedTemplateBundle getTemplateBundleFromResponse(object ResponseValue)
        {
            FeedTemplateBundle result = null;

            FacebookRequest request = new FacebookRequest(_session);

            //Call Facebook API
            FacebookResponse response = request.InvokeMethod("feed.registerTemplateBundle");
            JsonReader reader = new JsonReader(new StringReader(ResponseValue.ToString()));
            reader.ReadValue();

            return result;
        }

        private ICollection<FeedTemplateBundle> getTemplateBundlesFromResponse(object ResponseValue)
        {
            ICollection<FeedTemplateBundle> resultList = new List<FeedTemplateBundle>();

            //TODO resultList.Add(getTemplateBundleFromResponse(ResponseValue);

            return resultList;
        }

        /// <summary>
        /// Retrieves the full list of all the template bundles registered by the 
        /// requesting application. The list does not include any of the template 
        /// bundles previously deactivated via calls to feed.deactivateTemplateBundleByID.
        /// </summary>
        /// <returns></returns>
        public ICollection<FeedTemplateBundle> getRegisteredTemplateBundles()
        {
            FacebookRequest request = new FacebookRequest(_session);

            request.Parameters["format"] = "JSON";

            //Call Facebook API
            FacebookResponse response = request.InvokeMethod("feed.getRegisteredTemplateBundles");

            // if the result is false (failed) this property allows the developer to get access to 
            // the error codes returned from Facebook.
            _lastResponse = response;

            if (response.Status != FacebookResponseStatus.Succeeded)
                return null;

            return getTemplateBundlesFromResponse(response.Result);
            
        }

        /// <summary>
        /// Deactivates a previously registered template bundle. Once a template bundle has been deactivated, 
        /// it can no longer be used to publish stories via feed.publishUserAction.
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        public bool deactivateTemplateBundleByID(int ID)
        {
            FacebookRequest request = new FacebookRequest(_session);

            request.Parameters["format"] = "JSON";
            request.Parameters["template_bundle_id"] = ID.ToString();

            //Call Facebook API
            FacebookResponse response = request.InvokeMethod("feed.deactivateTemplateBundleByID");

            // if the result is false (failed) this property allows the developer to get access to 
            // the error codes returned from Facebook.
            _lastResponse = response;

            if (response.Status == FacebookResponseStatus.Succeeded)
            {
                return FacebookResponse.CoerceBoolean(response.Result);
            }

            return false;
        }
    }
}
